package com.yq.ylmall.product.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yq.ylmall.constant.ProductConstant;
import com.yq.ylmall.dto.product.*;
import com.yq.ylmall.enums.product.ProductCheck;
import com.yq.ylmall.enums.product.ProductStatus;
import com.yq.ylmall.exception.ServiceException;
import com.yq.ylmall.model.product.Product;
import com.yq.ylmall.model.product.ProductDetails;
import com.yq.ylmall.model.product.ProductSku;
import com.yq.ylmall.product.mapper.ProductMapper;
import com.yq.ylmall.product.service.IFileService;
import com.yq.ylmall.product.service.IProductDetailsService;
import com.yq.ylmall.product.service.IProductService;
import com.yq.ylmall.product.service.IProductSkuService;
import com.yq.ylmall.result.ResultCode;
import com.yq.ylmall.utils.SnowUtil;
import com.yq.ylmall.vo.product.ProductInfoVo;
import com.yq.ylmall.vo.product.ProductPageVo;
import com.yq.ylmall.vo.product.ProductSkuVo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestBody;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 商品 服务实现类
 * </p>
 *
 * @author yzk789
 * @since 2024-05-30
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> implements IProductService {

    private final IProductDetailsService productDetailsService;
    private final IProductSkuService productSkuMapper;
    private final IFileService fileService;
    private final RabbitTemplate rabbitTemplate;

    @Override
    public IPage<ProductPageVo> queryProduct(ProductQueryDto dto) {
        IPage<ProductPageVo> page = new Page<>(dto.getPageNum(), dto.getPageSize());
        return baseMapper.queryProduct(page, dto);
    }

    @Override
    public ProductInfoVo getProductInfoById(Long productId) {
        ProductInfoVo vo = baseMapper.getProductInfoById(productId);
        if (vo == null) return null;
        List<ProductSku> dbSkus = productSkuMapper.list(Wrappers.<ProductSku>lambdaQuery().eq(ProductSku::getProductId, productId));
        if (!dbSkus.isEmpty()) {
            List<ProductSkuVo> productSkuList = dbSkus.stream().map(sku -> BeanUtil.copyProperties(sku, ProductSkuVo.class)).collect(Collectors.toList());
            vo.setProductSkuList(productSkuList);
        }
        return vo;
    }

    @Override
    @Transactional
    public void operateProduct(ProductDto dto) {
        boolean updated = dto.getId() != null; // 是否更新
        Product product = new Product(); // 商品
        ProductDetails productDetails = new ProductDetails(); // 商品详情

        if (updated) {
            // 更新
            product.setId(dto.getId());
            // 查询商品详情的ID
            productDetails = productDetailsService.getOne(
                    Wrappers.<ProductDetails>lambdaQuery()
                            .select(ProductDetails::getId)
                            .eq(ProductDetails::getProductId, product.getId())
            );
        } else {
            // 新增，生成雪花ID
            product.setId(SnowUtil.getSnowflakeNextId());
            productDetails.setId(SnowUtil.getSnowflakeNextId());
        }

        // -------------- product表 --------------
        BeanUtils.copyProperties(dto, product);
        // 处理分类
        product = categoriesHandle(dto.getCategories(), product);
        product.setSpecValueId(dto.getSpecValueId());
        product.setStatus(ProductStatus.INIT);
        product.setAuditStatus(ProductCheck.NOT_CHECK);
        product.setAuditMessage(ProductCheck.NOT_CHECK.getDesc());
        // 有ID更新，无ID新增
        this.saveOrUpdate(product);

        // -------------- product_details表 --------------
        productDetails.setProductId(product.getId());
        productDetails.setProductDesc(dto.getProductDetails().getProductDesc());
        productDetails.setSliderUrls(dto.getProductDetails().getSliderUrls());
        productDetails.setImageUrls(dto.getProductDetails().getImageUrls());
        productDetailsService.saveOrUpdate(productDetails);

        // -------------- product_sku表 --------------
        int i = 1;
        for (ProductSkuDto skuDto : dto.getProductSkuList()) {
            ProductSku productSku = new ProductSku();
            if (updated) {
                productSku = productSkuMapper.getOne(
                        Wrappers.<ProductSku>lambdaQuery()
                                .select(ProductSku::getId)
                                .eq(ProductSku::getProductId, product.getId())
                                .eq(ProductSku::getId, skuDto.getId())
                );
            } else {
                productSku.setId(SnowUtil.getSnowflakeNextId());
                productSku.setSkuCode(product.getId() + "_" + (i++));
                productSku.setProductId(product.getId());
            }
            BeanUtils.copyProperties(skuDto, productSku);
            productSkuMapper.saveOrUpdate(productSku);
        }
    }

    @Override
    @Transactional
    public void removeProduct(Long id) {
        // 获取sku的图片执行删除图片逻辑，最后删除当前sku数据
        List<ProductSku> skuList = productSkuMapper.list(Wrappers.<ProductSku>lambdaQuery().select(ProductSku::getThumbImg).eq(ProductSku::getProductId, id));
        productSkuMapper.remove(Wrappers.<ProductSku>lambdaUpdate().eq(ProductSku::getProductId, id));
        // 获取商品详情的图片执行删除图片逻辑，最后删除当前商品详情数据
        List<ProductDetails> details = productDetailsService.list(
                Wrappers.<ProductDetails>lambdaQuery()
                        .select(ProductDetails::getImageUrls, ProductDetails::getSliderUrls)
                        .eq(ProductDetails::getProductId, id)
        );
        // 删除产品
        productDetailsService.remove(Wrappers.<ProductDetails>lambdaUpdate().eq(ProductDetails::getProductId, id));
        baseMapper.deleteById(id);
        // 执行删除图片逻辑
        List<String> thumbs = skuList.stream().map(ProductSku::getThumbImg).collect(Collectors.toList());
        fileService.removeFile(thumbs);
        for (ProductDetails detail : details) {
            String imageUrlsJson = detail.getImageUrls();
            List<String> imageUrls = Arrays.asList(imageUrlsJson.split(","));
            fileService.removeFile(imageUrls);
            String sliderUrlsJson = detail.getSliderUrls();
            List<String> sliderUrls = Arrays.asList(sliderUrlsJson.split(","));
            fileService.removeFile(sliderUrls);
        }
    }

    @Override
    public void checkProduct(ProductCheckDto dto) {
        baseMapper.update(
                null,
                Wrappers.<Product>lambdaUpdate()
                        .set(Product::getAuditStatus, dto.getAuditStatus())
                        .set(Product::getAuditMessage, dto.getAuditMessage())
                        .eq(Product::getId, dto.getId())
        );
    }

    @Override
    public void onSale(ProductSaleDto dto) {
        switch (dto.getStatus()) {
            case 0:
                log.info("商品初始化：{} TODO", dto.getId());
                break;
            case 1:
                log.info("上架商品：{}", dto.getId());
                Product upper = new Product();
                upper.setId(dto.getId());
                upper.setStatus(ProductStatus.SHELVES);
                baseMapper.updateById(upper);
                // 发送MQ消息
                rabbitTemplate.convertAndSend(
                        ProductConstant.PRODUCT_EXCHANGE,
                        ProductConstant.PRODUCT_UPPER_KEY,
                        dto.getId()
                );
                break;
            case 2:
                log.info("下架商品：{}", dto.getId());
                Product lower = new Product();
                lower.setId(dto.getId());
                lower.setStatus(ProductStatus.SELF_SHELVES);
                baseMapper.updateById(lower);
                // 发送MQ消息
                rabbitTemplate.convertAndSend(
                        ProductConstant.PRODUCT_EXCHANGE,
                        ProductConstant.PRODUCT_LOWER_KEY,
                        dto.getId()
                );
                break;
            default:
                throw new ServiceException(ResultCode.DATA_ERROR);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void decreaseStock(ProductDecreaseDto productDecrease) {
        Product product = super.getById(productDecrease.getProductId());
        if(product == null) {
            log.error("商品不存在：{}", productDecrease.getProductId());
            throw new RuntimeException(ResultCode.DATA_ERROR.getMessage());
        }
        if (product.getStatus() != ProductStatus.SHELVES) {
            log.error("商品状态：{}", product.getStatus());
            log.error("商品未上架：{}", product.getStatus());
            throw new RuntimeException(ResultCode.DATA_ERROR.getMessage());
        }

        ProductSku sku = productSkuMapper.getById(productDecrease.getSkuId());
        if (sku == null) {
            log.error("商品sku不存在：{}", productDecrease.getSkuId());
            throw new RuntimeException(ResultCode.DATA_ERROR.getMessage());
        }
        if (sku.getStockNum() < productDecrease.getCount()) {
            log.error("商品库存不足：{}", productDecrease.getCount());
            throw new RuntimeException(ResultCode.CREATE_ORDER_FAIL.getMessage());
        }
        productSkuMapper.update(
                null,
                Wrappers.<ProductSku>lambdaUpdate()
                        .set(ProductSku::getStockNum, sku.getStockNum() - productDecrease.getCount())
                        .set(ProductSku::getSaleNum, sku.getSaleNum() + productDecrease.getCount())
                        .eq(ProductSku::getSkuCode, productDecrease.getSkuId())
        );
    }

    /**
     * 处理商品分类字段
     *
     * @param ids     分类ID数组
     * @param product 处理的商品
     * @return Product
     */
    protected Product categoriesHandle(List<Long> ids, Product product) {
        if (ids == null) return product;
        switch (ids.size()) {
            case 0:
                break;
            case 1:
                product.setCategory1Id(ids.get(0));
                break;
            case 2:
                product.setCategory1Id(ids.get(0));
                product.setCategory2Id(ids.get(1));
                break;
            case 3:
                product.setCategory1Id(ids.get(0));
                product.setCategory2Id(ids.get(1));
                product.setCategory3Id(ids.get(2));
                break;
            default:
                throw new ServiceException(ResultCode.DATA_ERROR);
        }
        return product;
    }

}
